Skip to content

feat: redesign API reference page#56

Merged
rsbh merged 15 commits into
mainfrom
feat_api_reference_page
May 12, 2026
Merged

feat: redesign API reference page#56
rsbh merged 15 commits into
mainfrom
feat_api_reference_page

Conversation

@rsbh
Copy link
Copy Markdown
Member

@rsbh rsbh commented May 12, 2026

Summary

  • New read-only API overview page matching Figma design (two-column layout, field badges + types, code snippets, response panel)
  • Playground dialog opens via "Test request" navbar button with editable fields, JSON body editor, auth type switching (API Key, Bearer, Basic), live response with status/time/headers
  • "View documentation" button reads externalDocs from OpenAPI spec
  • Redesigned API sidebar with flat tag groups, method text right-aligned with semantic colors
  • Auto-generate operationId for endpoints missing it
  • Resolve allOf/oneOf/anyOf in schema flattening
  • Preserve externalDocs and securityDefinitions in Swagger 2.0 → OpenAPI 3.0 conversion
  • Clean up old API components replaced by api-v2

Test plan

  • Run bun run dev:examples:basic and navigate to API reference pages
  • Verify overview page shows read-only fields (Badge + type), two-column layout
  • Click "Test request" → dialog opens with editable fields
  • Fill auth/body fields, click Send → response shows with status + time
  • Toggle JSON body editor via </> icon
  • Switch response view between Body and Headers
  • "View documentation" button opens external docs URL
  • Sidebar shows flat tag groups with method text (GET green, POST blue)
  • Endpoints without operationId (e.g. /ping) appear in sidebar
  • Non-API pages still show normal sidebar and OpenInAI button

🤖 Generated with Claude Code

rsbh and others added 9 commits May 11, 2026 12:06
New api-v2 components replace EndpointPage with read-only view showing
field names and types without editable inputs. Playground dialog and
navbar actions to follow in subsequent commits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Layout: flex justify-between with px-32px, matching Figma content node
- ApiLayout: override parent content padding for horizontal control
- Sections: dividers between sections with proper margin
- Fields: Flex gap numbers, Badge micro size, Apsara CopyButton
- Code snippet: custom component with CodeBlock highlighting, language
  dropdown via Menu, title in header
- Response panel: custom status tabs (200/400/404/500), CodeBlock for
  JSON highlighting, shows {} for responses without examples
- Typography: all using Apsara design tokens and --rs-font-mono

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Read externalDocs URL from OpenAPI operation, fallback to spec level
- Preserve externalDocs in Swagger 2.0 → OpenAPI 3.0 conversion
- Shared useApiOperation() hook resolves current endpoint from URL
- Button shows in navbar only on API endpoint pages with docs URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Test request button in navbar opens playground dialog
- Split panel: editable fields left, response right
- Auth type selector: API Key, Bearer Token, Basic Auth from OpenAPI
  securitySchemes, fallback to chronicle.yaml auth config
- Preserve securityDefinitions in Swagger 2.0 → OpenAPI 3.0 conversion
- Send via /api/apis-proxy, shows status + response time
- Bottom bar with method badge, path, copy curl, Send button
- Dedup auth header from operation header parameters

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add kind field to SchemaField for reliable type detection
- Resolve allOf/oneOf/anyOf in flattenSchema for nested objects
- Auto-generate operationId for endpoints missing it (method + path)
- Array fields: add/remove UI for primitive arrays (string[], number[])
- Object fields: render child fields recursively with indented layout
- Reset dialog state on endpoint change via React key
- Field list gap and array item alignment fixes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Toggle between form fields and CodeMirror JSON editor via </> icon
- Two-way sync between form and JSON views
- Response panel dropdown to switch between Body and Headers view
- Proxy returns response headers from upstream
- Fix JsonEditor cursor reset by using ref for onChange callback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed: endpoint-page, field-section, field-row, key-value-editor,
code-snippets, response-panel. Kept: method-badge, json-editor (still
used by api-v2 and other components).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Flat tag groups with plain text headers (not collapsible accordions)
- Method text right-aligned in mono font with semantic colors
- GET=green (success), POST=blue (accent), PUT=yellow, DELETE=red
- Active item with neutral background highlight
- Consistent method colors across sidebar, method bar, and playground

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chronicle Ready Ready Preview, Comment May 12, 2026 10:33am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Warning

Rate limit exceeded

@rsbh has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 24 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a34ff11-8328-42f9-8ca1-9ecd5a780a23

📥 Commits

Reviewing files that changed from the base of the PR and between 0912fad and 3c1e106.

📒 Files selected for processing (18)
  • packages/chronicle/src/components/api/api-code-snippet.module.css
  • packages/chronicle/src/components/api/api-code-snippet.tsx
  • packages/chronicle/src/components/api/api-field-list.module.css
  • packages/chronicle/src/components/api/api-field-list.tsx
  • packages/chronicle/src/components/api/api-overview.module.css
  • packages/chronicle/src/components/api/api-overview.tsx
  • packages/chronicle/src/components/api/api-response-panel.module.css
  • packages/chronicle/src/components/api/api-response-panel.tsx
  • packages/chronicle/src/components/api/index.ts
  • packages/chronicle/src/components/api/playground-dialog.module.css
  • packages/chronicle/src/components/api/playground-dialog.tsx
  • packages/chronicle/src/lib/api-routes.ts
  • packages/chronicle/src/lib/openapi.ts
  • packages/chronicle/src/lib/schema.ts
  • packages/chronicle/src/pages/ApiPage.tsx
  • packages/chronicle/src/server/api/apis-proxy.ts
  • packages/chronicle/src/themes/default/Layout.module.css
  • packages/chronicle/src/themes/default/Layout.tsx
📝 Walkthrough

Walkthrough

This PR replaces the API documentation and playground UI with a new v2 implementation. It removes legacy api/* components (EndpointPage, CodeSnippets, FieldRow, etc.) and introduces new api-v2/* components (ApiOverview, PlaygroundDialog, ApiResponsePanel, ApiFieldSection). Supporting changes update OpenAPI schema handling, operation ID derivation, and sidebar navigation integration.

Changes

API v2 Component Suite

Layer / File(s) Summary
ApiOverview operation detail display
packages/chronicle/src/components/api-v2/api-overview.tsx, packages/chronicle/src/components/api-v2/api-overview.module.css
Renders OpenAPI operation summary with method/path, derives request parameters and body schema into field sections, extracts response sections by status code, and displays code snippet and response examples alongside the endpoint.
ApiFieldSection and child rendering
packages/chronicle/src/components/api-v2/api-field-list.tsx, packages/chronicle/src/components/api-v2/api-field-list.module.css
Component displays schema fields in titled sections with optional descriptions, renders individual fields with type/description/badges, and provides expandable children control for nested object attributes.
ApiCodeSnippet language-aware code generation
packages/chronicle/src/components/api-v2/api-code-snippet.tsx, packages/chronicle/src/components/api-v2/api-code-snippet.module.css
Memoized code snippet component with language selector (curl/python/go/typescript), generates request code via language-specific generators, and displays in copyable CodeBlock.
ApiResponsePanel tabbed response display
packages/chronicle/src/components/api-v2/api-response-panel.tsx, packages/chronicle/src/components/api-v2/api-response-panel.module.css
Renders tabbed response viewer allowing users to switch between HTTP status codes and view corresponding JSON example with copy functionality.
PlaygroundDialog interactive API client
packages/chronicle/src/components/api-v2/playground-dialog.tsx, packages/chronicle/src/components/api-v2/playground-dialog.module.css
Full-featured interactive API sandbox: manages auth scheme/token selection, path/query/header/body parameter input with JSON editor toggle, sends requests via proxy, displays response body or headers with status and elapsed time, generates curl snippets, and supports array editing with add/remove controls.
Api-v2 barrel export
packages/chronicle/src/components/api-v2/index.ts
Re-exports all five new API v2 components for public consumption.

OpenAPI & Schema Infrastructure

Layer / File(s) Summary
Schema composition and field metadata
packages/chronicle/src/lib/schema.ts
Introduces SchemaFieldKind type for field kind tracking, adds mergeAllOf helper to flatten allOf/oneOf/anyOf composition during schema flattening, and merges property schemas before type inference and child field generation.
OpenAPI v2 security scheme conversion
packages/chronicle/src/lib/openapi.ts
Adds convertV2SecurityDefs helper to map v2 securityDefinitions (apiKey, basic, oauth2) into v3 SecuritySchemeObject structures and includes them in v3 output's components.securitySchemes block.
Operation ID derivation and routing
packages/chronicle/src/lib/api-routes.ts
Introduces deriveOperationId (method + path slug) and getOperationId (prefers explicit operationId with fallback), updates route building and operation lookup to work with derived IDs even when operationId is absent, and updates page tree generation accordingly.
useApiOperation hook
packages/chronicle/src/lib/use-api-operation.ts
New React hook that derives API operation from current pathname (stripping /apis/ prefix) and resolves via findApiOperation, returning matched operation or null, memoized on pathname and spec changes.

UI Integration & Legacy Migration

Layer / File(s) Summary
ApiPage integration
packages/chronicle/src/pages/ApiPage.tsx
Switches from EndpointPage to ApiOverview for rendering matched API operation details.
Layout sidebar and playground integration
packages/chronicle/src/themes/default/Layout.tsx, packages/chronicle/src/themes/default/Layout.module.css
Adds ApiSidebarNode component to render API items in sidebar with HTTP method labels/colors, introduces TestRequestButton that opens PlaygroundDialog for matched operation, adds ViewDocsButton opening external docs or spec, and wires these into the card sub-navigation for API routes. Includes new CSS classes for API group styling.
JsonEditor callback optimization
packages/chronicle/src/components/api/json-editor.tsx
Uses useRef to store onChange callback, decoupling it from editor setup effect dependencies to avoid recreating the editor on callback changes.
MethodBadge variant adjustment
packages/chronicle/src/components/api/method-badge.tsx
Swaps color variants: GET now uses success, POST uses accent.
Response headers preservation in proxy
packages/chronicle/src/server/api/apis-proxy.ts
Proxy handler now collects and includes upstream response headers in JSON response payload alongside status/statusText/body.
ApiLayout content padding reset
packages/chronicle/src/pages/ApiLayout.module.css
Adds padding-left: 0 to .content rule.
Legacy API components removal
packages/chronicle/src/components/api/index.ts, packages/chronicle/src/components/api/endpoint-page.tsx, packages/chronicle/src/components/api/field-row.tsx, packages/chronicle/src/components/api/field-section.tsx, packages/chronicle/src/components/api/code-snippets.tsx, packages/chronicle/src/components/api/response-panel.tsx, packages/chronicle/src/components/api/key-value-editor.tsx, and associated CSS modules
Removes old API v1 implementation: EndpointPage (editable endpoint UI), FieldRow (field editing), FieldSection (section tabs), CodeSnippets, ResponsePanel, and KeyValueEditor; narrows barrel export to only MethodBadge and JsonEditor.

Sequence Diagram

sequenceDiagram
    participant User
    participant PlaygroundDialog
    participant ApiProxyServer
    participant UpstreamAPI

    User->>PlaygroundDialog: Fill parameters & auth
    User->>PlaygroundDialog: Click Send
    PlaygroundDialog->>PlaygroundDialog: Resolve path template
    PlaygroundDialog->>PlaygroundDialog: Build query string
    PlaygroundDialog->>PlaygroundDialog: Merge headers
    PlaygroundDialog->>ApiProxyServer: POST /api/apis-proxy {method, path, headers, body}
    ApiProxyServer->>UpstreamAPI: Forward request
    UpstreamAPI-->>ApiProxyServer: Response {status, headers, body}
    ApiProxyServer-->>PlaygroundDialog: {status, statusText, headers, body, responseTime}
    PlaygroundDialog->>PlaygroundDialog: Render response
    PlaygroundDialog->>User: Display body/headers with status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • raystack/chronicle#24: Both PRs modify packages/chronicle/src/server/api/apis-proxy.ts to change response serialization (this PR adds headers preservation).
  • raystack/chronicle#16: Both PRs modify sidebar navigation and API-related UI in Layout.tsx/Layout.module.css to integrate API endpoints into the navigation.
  • raystack/chronicle#11: This PR refactors the entire API feature set added in PR #11—both modify API routing, OpenAPI utilities, and UI components, with this PR introducing api-v2 replacements and removing the original api/* implementations.

Suggested reviewers

  • rohanchkrabrty
  • rohilsurana
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: redesign API reference page' directly and clearly summarizes the main change - a comprehensive redesign of the API reference UI (api-v2), matching the PR objectives and changeset scope.
Description check ✅ Passed The description is well-related to the changeset, detailing key features (overview page, playground dialog, sidebar redesign, schema improvements) and includes a test plan, all aligned with the actual file modifications.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat_api_reference_page

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- Merge method-badge and json-editor into api folder
- Remove api-v2 directory, update all imports
- Use Flex components for API sidebar nodes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/chronicle/src/lib/schema.ts (1)

76-86: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate schema type before casting to SchemaFieldKind.

Line 79 casts prop.type to SchemaFieldKind without validation. If the OpenAPI schema contains non-standard or extended types (e.g., 'null', custom types), the cast will succeed but produce an invalid kind value that doesn't match the union type at runtime. This could cause downstream UI rendering issues or type guards to fail.

🛡️ Proposed fix with validation
+const validKinds: SchemaFieldKind[] = ['string', 'integer', 'number', 'boolean', 'array', 'object']
+function toKind(type: unknown): SchemaFieldKind {
+  if (typeof type === 'string' && validKinds.includes(type as SchemaFieldKind)) {
+    return type as SchemaFieldKind
+  }
+  return 'object'
+}

       return {
         name,
         type: fieldType,
-        kind: (prop.type as SchemaFieldKind) ?? 'object',
+        kind: toKind(prop.type),
         required: required.includes(name),
         description: rawProp.description ?? prop.description,
         default: prop.default,
         enum: prop.enum,
         children: children?.length ? children : undefined,
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/lib/schema.ts` around lines 76 - 86, The code
currently casts prop.type to SchemaFieldKind directly when building the returned
field object (the kind property), which can accept invalid runtime values;
change this to validate prop.type against the allowed SchemaFieldKind union
before assigning: implement or use a small validator (e.g.,
isValidSchemaFieldKind) that checks prop.type against the set of permitted kinds
and only then set kind = prop.type as SchemaFieldKind, otherwise fall back to
'object' (or another safe default); update the object creation where kind is set
(the line using (prop.type as SchemaFieldKind) ?? 'object') to use this
validation helper so downstream consumers get only known kinds.
🧹 Nitpick comments (5)
packages/chronicle/src/components/api-v2/api-response-panel.tsx (1)

5-5: 💤 Low value

Prefer repo path alias for consistency with TS/TSX import policy.

Use the @/* alias instead of a relative path for this import, if CSS-module alias resolution is configured in this workspace.

As per coding guidelines, **/*.{ts,tsx}: Use path alias @/* → ./src/* configured in tsconfig and vite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/components/api-v2/api-response-panel.tsx` at line 5,
Replace the relative CSS import in the API response panel component with the
repo path alias: change the import statement that currently reads "import styles
from './api-response-panel.module.css'" in the api-response-panel.tsx module to
use the `@/` alias (e.g. import styles from
'@/components/api-v2/api-response-panel.module.css') so it follows the project's
TypeScript/Vite path-alias convention; ensure the aliased path matches your
tsconfig/vite alias mapping and that the file location corresponds to that
alias.
packages/chronicle/src/components/api-v2/api-field-list.tsx (1)

58-86: 💤 Low value

Consider avoiding non-null assertion operator.

Line 79 uses field.children! with a non-null assertion. While safe because ExpandableChildren is only called when hasChildren is true (line 53), TypeScript best practice is to avoid ! operators when the type can be narrowed through explicit checks.

♻️ Alternative approach
 function ExpandableChildren({ field }: { field: SchemaField }) {
   const [expanded, setExpanded] = useState(false)
+  if (!field.children || field.children.length === 0) return null

   return (
     <Flex direction="column">
       <button
         type="button"
         className={styles.expandButton}
         onClick={() => setExpanded(!expanded)}
       >
         <span className={styles.expandLabel}>
           {expanded ? 'Hide' : 'Show'} child attributes
         </span>
         {expanded ? (
           <ChevronDownIcon width={16} height={16} />
         ) : (
           <ChevronRightIcon width={16} height={16} />
         )}
       </button>
       {expanded && (
         <div className={styles.childFields}>
-          {field.children!.map((child) => (
+          {field.children.map((child) => (
             <FieldItem key={child.name} field={child} />
           ))}
         </div>
       )}
     </Flex>
   )
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/components/api-v2/api-field-list.tsx` around lines 58
- 86, The code uses a non-null assertion on field.children in
ExpandableChildren; replace it with an explicit type-narrowing check to avoid
"!" — for example, at the top of ExpandableChildren return early if
(!field.children || field.children.length === 0) return null, or change the JSX
to use optional chaining (field.children?.map(...)) inside the expanded block;
update the rendering logic around the expanded conditional accordingly so
TypeScript knows children is present without using the non-null operator.
packages/chronicle/src/components/api-v2/api-overview.tsx (2)

68-103: ⚖️ Poor tradeoff

Reduce separator logic duplication.

The code repeats separator conditional logic between each section pair (lines 72-74, 80-82, 88-90, 96-98). This violates DRY and makes it harder to reorder or add/remove sections. Consider extracting the sections into an array and rendering separators programmatically between non-empty sections.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/components/api-v2/api-overview.tsx` around lines 68 -
103, The repeated Separator conditional logic can be removed by building an
ordered array of section descriptors (e.g., objects with keys like
id/title/component and a predicate based on authFields, pathFields, queryFields,
body?.fields.length, responses) and then mapping that array to render only the
non-empty sections; between mapped items insert a single Separator (using
Separator and styles.divider) for every index > 0, rendering ApiFieldSection for
items referencing authFields/pathFields/queryFields/body.fields and
ResponseSection for the responses item; update the JSX in api-overview.tsx to
compute visibleSections before return and render them in a single map so
adding/reordering sections no longer requires duplicated separator conditionals.

158-170: ⚡ Quick win

Handle composed schemas in parameter conversion.

The paramsToFields function directly reads schema.type without applying mergeAllOf or other composition logic (line 163-164). If an OpenAPI parameter schema uses allOf, oneOf, or anyOf to compose types, the function will fail to extract the correct type and may produce 'string' as a fallback even when the composed type is different.

This inconsistency with the flattenSchema approach used for request/response bodies could lead to incorrect parameter type displays in the UI.

♻️ Proposed fix using existing schema utilities
+import { flattenSchema } from '@/lib/schema'
+
 function paramsToFields(params: OpenAPIV3.ParameterObject[]): SchemaField[] {
   return params.map((p) => {
     const schema = (p.schema ?? {}) as OpenAPIV3.SchemaObject
+    // For simple params, flatten returns a single-item array or empty
+    const flattened = flattenSchema(schema)
+    const field = flattened[0]
     return {
       name: p.name,
-      type: schema.type ? String(schema.type) : 'string',
-      kind: (schema.type as SchemaField['kind']) ?? 'string',
+      type: field?.type ?? (schema.type ? String(schema.type) : 'string'),
+      kind: field?.kind ?? ((schema.type as SchemaField['kind']) ?? 'string'),
       required: p.required ?? false,
       description: p.description,
       default: schema.default,
     }
   })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/components/api-v2/api-overview.tsx` around lines 158 -
170, The paramsToFields function reads p.schema.type directly and doesn't handle
composed schemas; fix it by first flattening/merging the parameter schema (e.g.,
call the existing flattenSchema or mergeAllOf utility on (p.schema ?? {})) and
then derive type, kind, default, and description from the flattened schema
instead of p.schema; update paramsToFields to use the flattened schema when
computing type/kind (falling back to 'string') while preserving required,
description, and default values.
packages/chronicle/src/components/api-v2/playground-dialog.tsx (1)

346-353: 💤 Low value

Consider notifying user when JSON-to-form sync fails.

When toggling from JSON mode back to form mode, parse errors are silently ignored (line 350). If the user has entered invalid JSON, their edits are lost without feedback. While less critical than request-time errors, a console warning or toast notification would improve the user experience.

ℹ️ Optional enhancement
                       } else {
-                        try { setBodyValues(JSON.parse(bodyJsonStr)) } catch { /* ignore */ }
+                        try { 
+                          setBodyValues(JSON.parse(bodyJsonStr)) 
+                        } catch (e) {
+                          console.warn('Failed to parse JSON, keeping previous form values:', e)
+                        }
                       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/components/api-v2/playground-dialog.tsx` around lines
346 - 353, The JSON->form toggle handler currently swallows parse errors (inside
the IconButton onClick) causing user edits to be lost; update the try/catch
around JSON.parse(bodyJsonStr) in that click handler to catch the error, surface
feedback (e.g., show a toast or call console.warn with the parse error and a
user-friendly message referencing bodyJsonStr), and prevent flipping
setJsonMode(!jsonMode) when parsing fails so the user remains in JSON mode and
retains their edits; use the existing state setters setBodyValues,
setBodyJsonStr and jsonMode to implement this behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/chronicle/src/components/api-v2/api-code-snippet.module.css`:
- Around line 27-29: The CSS module is missing explicit Shiki token color
bindings for inline code spans; update the stylesheet to add rules targeting the
code container selector (e.g. .pre code span) to set color via the Shiki tokens
(use --shiki-light for the default/light theme) and add a dark-theme override
(e.g. a [data-theme="dark"] or .dark root selector) that sets .pre code span to
--shiki-dark; keep the selectors scoped to the same module (reference the
existing .body and the code-snippet container) so Shiki-highlighted spans
inherit the correct light/dark colors.

In `@packages/chronicle/src/components/api-v2/api-code-snippet.tsx`:
- Around line 32-35: The memoized `code` uses useMemo with the wrong dependency
(`selected`) causing stale results because the generator comes from `current`;
change the dependency array to include the actual generator source (`current`)
and the other inputs (`method`, `url`, `headers`, `body`) so the memo recomputes
whenever `current` (which is derived from `selected`/`languages`) or any input
changes; update the useMemo call that assigns `code` (currently calling
`current.generate(...)`) to depend on `current`, `method`, `url`, `headers`, and
`body` instead of `selected`.

In `@packages/chronicle/src/components/api-v2/api-overview.tsx`:
- Around line 121-125: ResponseSection should defensively handle an empty
responses array: change the selectedStatus initial state from the hardcoded
'200' to use responses[0]?.status ?? '' (e.g., useState(() =>
responses[0]?.status ?? '')) and compute active with const active =
responses.find(r => r.status === selectedStatus); then keep the early guard if
(!active) return null; this ensures no properties on an undefined active are
accessed when responses is empty while preserving hook usage in ResponseSection
and symbols selectedStatus, setSelectedStatus, active, and responses.

In `@packages/chronicle/src/components/api-v2/api-response-panel.module.css`:
- Around line 76-79: The module is missing explicit Shiki token color rules for
the response code view; update the CSS for the .codeBlock/.pre code elements to
add light and dark Shiki span color bindings (e.g. add rules targeting ".pre
code span" and a dark-mode variant such as ".dark .pre code span" or
":global(.dark) .pre code span") so that each token uses the CSS vars (e.g.
var(--shiki-light) and var(--shiki-dark)); ensure these selectors are placed
alongside the existing .codeBlock rule in api-response-panel.module.css and
cover all span tokens emitted by Shiki.

In `@packages/chronicle/src/components/api-v2/playground-dialog.module.css`:
- Around line 218-220: The .statusValue CSS rule uses a hard-coded hex color
(`#30a46c`); update this to use the Apsara design token pattern (e.g., replace the
hex with var(--rs-color-success) or the appropriate --rs-color-* token) so the
status color follows the design system and supports theming; modify the
.statusValue declaration to reference the chosen --rs-color-* variable instead
of the literal `#30a46c`.

In `@packages/chronicle/src/components/api-v2/playground-dialog.tsx`:
- Around line 125-134: The reset logic inside setBodyValues currently detects
arrays using f.type.endsWith('[]') which is inconsistent with the initial-state
logic that uses f.kind === 'array'; update the reset handler (the block that
iterates body.fields inside setBodyValues) to use the same array detection as
the initializer (use f.kind === 'array', or a unified helper check) so array
fields are initialized and reset to the same shape (empty array) and
object/primitive fields follow the same rules (f.children -> {}, else '').
- Around line 193-197: The curlSnippet useMemo currently always stringifies
bodyValues; update it to respect jsonMode by using bodyJsonStr when jsonMode is
true (and fall back to JSON.stringify(bodyValues) when false) so the generated
cURL matches what handleSend actually sends; also add jsonMode and bodyJsonStr
to the useMemo dependency array so the snippet updates when JSON mode or the raw
JSON body changes. Ensure you modify the generateCurl call inside the useMemo
(curlSnippet) and adjust the dependency list accordingly.
- Around line 29-30: The code uses scheme.name! when building the schemes entry
in the conditional inside the playground dialog; update the guard to ensure
scheme.name is a non-empty string (e.g., check typeof scheme.name === 'string'
&& scheme.name.trim() !== '') before using it, and if it's missing/empty either
skip pushing this scheme or use a safe fallback like 'api_key' (adjust the
schemes.push call that creates { name: `API Key (${scheme.name})`, headerName:
scheme.name, ... } to use the validated value or fallback).
- Around line 160-164: The current jsonMode branch silently swallows JSON.parse
errors and falls back to bodyValues; instead, when parsing bodyJsonStr inside
the jsonMode branch (where reqBody, bodyJsonStr, bodyValues and jsonMode are
used), catch the error, set a visible parse error (e.g., set a local state like
jsonParseError or call the existing UI feedback mechanism/toast) with the
error.message, and prevent sending the request until the user fixes the JSON;
only assign reqBody = JSON.parse(bodyJsonStr) when parsing succeeds.

In `@packages/chronicle/src/lib/api-routes.ts`:
- Around line 10-12: deriveOperationId can produce an empty or colliding ID for
root/empty paths; update the function (deriveOperationId) to sanitize the path
as before but if the result after replacements is empty, substitute a stable
fallback (e.g., "root" or "empty") and return the method + "_" + fallback; also
normalize case (lowercase) and still collapse duplicate underscores so the final
operation id is always non-empty and deterministic.

In `@packages/chronicle/src/lib/openapi.ts`:
- Around line 143-145: The conversion for OAuth2 security schemes currently sets
result[name] = { type: 'oauth2', flows: {} } and drops v2 fields; update the
conversion in the function handling def (the v2 security definition) so you map
v2.flow -> the appropriate OpenAPIv3 flows object (authorizationCode, implicit,
password, clientCredentials), copy authorizationUrl and tokenUrl into the
corresponding flow object, and transfer scopes into flow.scopes; ensure the
created value remains typed as OpenAPIV3.OAuth2SecurityScheme and replace the
empty flows object assigned to result[name] with the fully populated flows
structure derived from def.flow, def.authorizationUrl, def.tokenUrl, and
def.scopes.

In `@packages/chronicle/src/server/api/apis-proxy.ts`:
- Around line 54-61: The proxied response currently echoes all upstream headers
via responseHeaders which can leak sensitive/internal headers; change the header
collection to filter out unsafe headers by using an allowlist (e.g.,
content-type, content-length, cache-control, etag, last-modified,
content-encoding) or at minimum explicitly exclude known unsafe/hop-by-hop
headers (e.g., set-cookie, cookie, connection, transfer-encoding, keep-alive,
proxy-authenticate, proxy-authorization, te, trailers, upgrade and any
infrastructure-specific headers) before populating responseHeaders; update the
code that iterates response.headers (the responseHeaders variable population in
apis-proxy.ts) to only copy allowed headers (or skip the blacklist) so the
returned Response.json contains only safe headers.

---

Outside diff comments:
In `@packages/chronicle/src/lib/schema.ts`:
- Around line 76-86: The code currently casts prop.type to SchemaFieldKind
directly when building the returned field object (the kind property), which can
accept invalid runtime values; change this to validate prop.type against the
allowed SchemaFieldKind union before assigning: implement or use a small
validator (e.g., isValidSchemaFieldKind) that checks prop.type against the set
of permitted kinds and only then set kind = prop.type as SchemaFieldKind,
otherwise fall back to 'object' (or another safe default); update the object
creation where kind is set (the line using (prop.type as SchemaFieldKind) ??
'object') to use this validation helper so downstream consumers get only known
kinds.

---

Nitpick comments:
In `@packages/chronicle/src/components/api-v2/api-field-list.tsx`:
- Around line 58-86: The code uses a non-null assertion on field.children in
ExpandableChildren; replace it with an explicit type-narrowing check to avoid
"!" — for example, at the top of ExpandableChildren return early if
(!field.children || field.children.length === 0) return null, or change the JSX
to use optional chaining (field.children?.map(...)) inside the expanded block;
update the rendering logic around the expanded conditional accordingly so
TypeScript knows children is present without using the non-null operator.

In `@packages/chronicle/src/components/api-v2/api-overview.tsx`:
- Around line 68-103: The repeated Separator conditional logic can be removed by
building an ordered array of section descriptors (e.g., objects with keys like
id/title/component and a predicate based on authFields, pathFields, queryFields,
body?.fields.length, responses) and then mapping that array to render only the
non-empty sections; between mapped items insert a single Separator (using
Separator and styles.divider) for every index > 0, rendering ApiFieldSection for
items referencing authFields/pathFields/queryFields/body.fields and
ResponseSection for the responses item; update the JSX in api-overview.tsx to
compute visibleSections before return and render them in a single map so
adding/reordering sections no longer requires duplicated separator conditionals.
- Around line 158-170: The paramsToFields function reads p.schema.type directly
and doesn't handle composed schemas; fix it by first flattening/merging the
parameter schema (e.g., call the existing flattenSchema or mergeAllOf utility on
(p.schema ?? {})) and then derive type, kind, default, and description from the
flattened schema instead of p.schema; update paramsToFields to use the flattened
schema when computing type/kind (falling back to 'string') while preserving
required, description, and default values.

In `@packages/chronicle/src/components/api-v2/api-response-panel.tsx`:
- Line 5: Replace the relative CSS import in the API response panel component
with the repo path alias: change the import statement that currently reads
"import styles from './api-response-panel.module.css'" in the
api-response-panel.tsx module to use the `@/` alias (e.g. import styles from
'@/components/api-v2/api-response-panel.module.css') so it follows the project's
TypeScript/Vite path-alias convention; ensure the aliased path matches your
tsconfig/vite alias mapping and that the file location corresponds to that
alias.

In `@packages/chronicle/src/components/api-v2/playground-dialog.tsx`:
- Around line 346-353: The JSON->form toggle handler currently swallows parse
errors (inside the IconButton onClick) causing user edits to be lost; update the
try/catch around JSON.parse(bodyJsonStr) in that click handler to catch the
error, surface feedback (e.g., show a toast or call console.warn with the parse
error and a user-friendly message referencing bodyJsonStr), and prevent flipping
setJsonMode(!jsonMode) when parsing fails so the user remains in JSON mode and
retains their edits; use the existing state setters setBodyValues,
setBodyJsonStr and jsonMode to implement this behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 43081ba5-494e-4aaf-a560-0079153fe47c

📥 Commits

Reviewing files that changed from the base of the PR and between 1d999e0 and 0912fad.

📒 Files selected for processing (35)
  • packages/chronicle/src/components/api-v2/api-code-snippet.module.css
  • packages/chronicle/src/components/api-v2/api-code-snippet.tsx
  • packages/chronicle/src/components/api-v2/api-field-list.module.css
  • packages/chronicle/src/components/api-v2/api-field-list.tsx
  • packages/chronicle/src/components/api-v2/api-overview.module.css
  • packages/chronicle/src/components/api-v2/api-overview.tsx
  • packages/chronicle/src/components/api-v2/api-response-panel.module.css
  • packages/chronicle/src/components/api-v2/api-response-panel.tsx
  • packages/chronicle/src/components/api-v2/index.ts
  • packages/chronicle/src/components/api-v2/playground-dialog.module.css
  • packages/chronicle/src/components/api-v2/playground-dialog.tsx
  • packages/chronicle/src/components/api/code-snippets.module.css
  • packages/chronicle/src/components/api/code-snippets.tsx
  • packages/chronicle/src/components/api/endpoint-page.module.css
  • packages/chronicle/src/components/api/endpoint-page.tsx
  • packages/chronicle/src/components/api/field-row.module.css
  • packages/chronicle/src/components/api/field-row.tsx
  • packages/chronicle/src/components/api/field-section.module.css
  • packages/chronicle/src/components/api/field-section.tsx
  • packages/chronicle/src/components/api/index.ts
  • packages/chronicle/src/components/api/json-editor.tsx
  • packages/chronicle/src/components/api/key-value-editor.module.css
  • packages/chronicle/src/components/api/key-value-editor.tsx
  • packages/chronicle/src/components/api/method-badge.tsx
  • packages/chronicle/src/components/api/response-panel.module.css
  • packages/chronicle/src/components/api/response-panel.tsx
  • packages/chronicle/src/lib/api-routes.ts
  • packages/chronicle/src/lib/openapi.ts
  • packages/chronicle/src/lib/schema.ts
  • packages/chronicle/src/lib/use-api-operation.ts
  • packages/chronicle/src/pages/ApiLayout.module.css
  • packages/chronicle/src/pages/ApiPage.tsx
  • packages/chronicle/src/server/api/apis-proxy.ts
  • packages/chronicle/src/themes/default/Layout.module.css
  • packages/chronicle/src/themes/default/Layout.tsx
💤 Files with no reviewable changes (13)
  • packages/chronicle/src/components/api/code-snippets.module.css
  • packages/chronicle/src/components/api/key-value-editor.module.css
  • packages/chronicle/src/components/api/endpoint-page.tsx
  • packages/chronicle/src/components/api/response-panel.module.css
  • packages/chronicle/src/components/api/field-section.module.css
  • packages/chronicle/src/components/api/endpoint-page.module.css
  • packages/chronicle/src/components/api/field-row.module.css
  • packages/chronicle/src/components/api/code-snippets.tsx
  • packages/chronicle/src/components/api/field-section.tsx
  • packages/chronicle/src/components/api/response-panel.tsx
  • packages/chronicle/src/components/api/index.ts
  • packages/chronicle/src/components/api/field-row.tsx
  • packages/chronicle/src/components/api/key-value-editor.tsx

Comment thread packages/chronicle/src/components/api/api-code-snippet.module.css
Comment thread packages/chronicle/src/components/api/api-code-snippet.tsx
Comment thread packages/chronicle/src/components/api/api-overview.tsx
Comment thread packages/chronicle/src/components/api/api-response-panel.module.css
Comment thread packages/chronicle/src/components/api/playground-dialog.module.css
Comment thread packages/chronicle/src/components/api/playground-dialog.tsx
Comment thread packages/chronicle/src/components/api/playground-dialog.tsx Outdated
Comment thread packages/chronicle/src/lib/api-routes.ts
Comment thread packages/chronicle/src/lib/openapi.ts
Comment thread packages/chronicle/src/server/api/apis-proxy.ts
- api-overview: layout, left, right, titleBlock, titleText, methodBar
- api-field-list: fieldItem, expandButton, childFields
- api-code-snippet: actions
- api-response-panel: wrapper, container, header, tabs
- playground-dialog: actionNav, splitPanel, leftPanel, panelHeader,
  sectionHeader, fieldRow (partial)
- sidebar: apiGroup, apiGroupItems, apiItem
- Remove redundant CSS layout properties handled by Flex

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Validate schema type with toKind() instead of unsafe cast
- Derive SchemaFieldKind type from map keys
- Fix useMemo dependency in ApiCodeSnippet (current.generate not selected)
- Null safety for empty responses in ResponseSection
- Replace hard-coded #30a46c with --rs-color-foreground-success-primary
- Guard against undefined scheme.name in auth schemes
- Unify array detection using kind field in reset handler
- Filter sensitive headers (set-cookie, authorization) from proxy response

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reverted partial Flex replacement that broke JSX tag matching.
Reapplied CodeRabbit fixes: toKind(), scheme.name guard, kind-based
array detection in reset handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Handle root/empty path in deriveOperationId (fallback to 'root')
- Curl snippet reflects JSON mode when body editor is active
- Show error on invalid JSON body instead of silent fallback
- Preserve OAuth2 flow details in Swagger 2.0 → 3.0 conversion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rsbh rsbh requested a review from rohanchkrabrty May 12, 2026 10:58
@rsbh rsbh merged commit 4b4857e into main May 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants